//
// Created by 张朝辉 on 2023/10/8.
//

#include "dpda.h"
#include <iostream>

DPDA::DPDA(std::set<std::string> state_set, std::set<char> char_set, std::set<char> stack_charset,
         std::map<Tuple3, std::pair<std::string, std::string>> rule_table, std::string start_state, char start_char, std::set<std::string> final_set)
         :state_set(state_set),char_set(char_set),stack_charset(stack_charset),rule_table(rule_table),
         start_state(start_state),start_char(start_char),final_set(final_set){
    sk.push('#');
    now_state = {start_state,sk.top()};      // 设置自动机初始状态
}

/*
 * 状态转换，转换成功返回true并修改自动机当前状态，否则返回false
 */
auto DPDA::state_transition(Tuple3 t) -> bool {
    auto it = rule_table.find(t);
    if(it != rule_table.end()){
        now_state.first = it->second.first;           // 修改当前自动机状态
        std::string str = it->second.second;
        if(str == "\0"){                 // 也可写为 str == ""
            sk.pop();
            now_state.second = sk.top();         // 修改自动机栈顶数据
        }
        // 默认情况下，如果str长度为1，则对栈不执行任何操作
        // 如果str的长度大于1，说明有新的符号入栈
        if(str.length() > 1){
            std::reverse(str.begin(),str.end());       // 将原来的栈顶元素出栈，将新的字符压栈
            sk.pop();
            for(auto c: str){
                sk.push(c);
            }
            now_state.second = sk.top();
        }
        return true;
    } else{
        return false;
    }
}

/*
 * 判断某个字符串能否被此DPDA接受
 */
auto DPDA::isAccept_str(std::string str) -> bool {
    int i = 0;
    while (i < str.length()){
        if(state_transition(Tuple3{now_state.first,str[i],now_state.second})){     // 如果当前字符在规则表中有对应规则，则根据规则修改当前状态
            i++;         // 识别下一个字符
        }else if(!state_transition(Tuple3{now_state.first,'\0',now_state.second})){  // 如果存在识别空字符的规则则进行状态转换，否则退出
            break;
        }
    }
    // 识别空串
    while (state_transition(Tuple3{now_state.first,'\0',now_state.second}));
    if(final_set.find(now_state.first) != final_set.end()){return true;}

    return false;
}

auto DPDA::description() -> void {
    std::cout<<"-------------------------------------当前DPDA详情----------------------------------------"<<std::endl;
    std::cout<<"状态集：{ ";
    for(auto &s: state_set){
        std::cout<<s<<" ";
    }
    std::cout<<"}"<<std::endl;
    std::cout<<"字符集：{ ";
    for(auto &s: char_set){
        std::cout<<s<<" ";
    }
    std::cout<<"}"<<std::endl;
    std::cout<<"栈字符集：{ ";
    for(auto &s: stack_charset){
        std::cout<<s<<" ";
    }
    std::cout<<"}"<<std::endl;
    std::cout<<"开始状态："<<start_state<<std::endl;
    std::cout<<"栈起始符号："<<start_char<<std::endl;
    std::cout<<"接受状态集：{ ";
    for(auto &s: final_set){
        std::cout<<s<<" ";
    }
    std::cout<<"}"<<std::endl;
    std::cout<<"状态转换表：{ ";
    for(auto &r: rule_table){
        std::cout<<"δ("<<r.first.q<<","<<r.first.a<<r.first.x<<") = ("<<r.second.first<<","<<r.second.second<<")\t";
    }
    std::cout<<"}"<<std::endl;
    std::cout<<"----------------------------------------------------------------------------------------"<<std::endl;
}
